查看原文
其他

用 Python 动态曲线图来对全球疫情进行演示

我是阳哥 Python数据之道 2022-09-04


作者:Lemon

出品:Python数据之道



用 Python 动态曲线图来对全球疫情进行演示


各位同学好,我是 Lemon 。
最近一段时间,我写了几篇用 Python 的交互式可视化工具 Plotly 来演示全球疫情情况的文章,如下:
如今(截至3月28日),全球确诊数量超过60万人,美国确诊数量已超过10万人,成为目前人数最多的国家,而且,疫情扩散的趋势还在快速发展过程中,多个国家首脑或高官也确诊,总体情况令人担忧,多国经济陷入困境,金融市场动荡不安。
今天,Lemon 继续来分享用 Plotly 对疫情情况进行可视化,本次我们用动态曲线图来进行演示。先来看最终的效果:


数据来源

本次我们主要使用动态曲线来可视化分析疫情的发展情况,疫情的数据来源于开源项目 Akshare 。为了代码和演示情况能够复现,这里我提供了保存好的数据供大家练习使用,本文的完整代码及数据文件在文末提供了获取方式。

准备工作

照例,还是先介绍下我运行的环境。
  • Mac 系统

  • Anaconda(Python 3.7)

  • Jupyter Notebook

我是在 Jupyter Notebook 中运行代码的,本次使用到的 Python 库包括 akshare, pandas, plotly 等,首先我们需要将这些工具进行导入。
接着,我们读取已获得的数据(已保存的数据是截至3月28日)。
  1. # 从 akshare 获取数据

  2. # df_all_history = ak.epidemic_history()


  3. # 从csv文件获取数据,这个数据文件的数据截止到3月28日

  4. df_all_history = pd.read_csv('epidemic_all_20200328.csv',index_col=0)


  5. df_all_history

获取数据后,根据本次数据分析和可视化的目的,Lemon 对数据进行了初步整理
  1. # 整理数据


  2. # 将数据复制一份

  3. df_all = df_all_history


  4. # 将字符串格式的日期 另保存为一列

  5. # df_all['dates'] = df_all_history['date']


  6. # 将字符串格式的日期转换为 日期格式

  7. df_all['date'] = pd.to_datetime(df_all['date'])


  8. # 将时间格式转为字符串格式的日期,以 YYYY-mm-dd 的形式保存

  9. df_all['dates'] = df_all['date'].apply(lambda x:x.strftime('%Y-%m-%d'))


  10. # 添加现存确诊列

  11. df_all['current'] = df_all['confirmed'] - df_all['cured'] - df_all['dead']


  12. df_all.fillna('', inplace=True)


  13. print(df_all.info())


  14. df_all

获取国外和国内的疫情数据

上面的数据,是全球的数据,其中也包括国内各个省市的数据。我们可以将数据进行整理,分别提取出中国和海外国家的数据。
  1. # 国内总计数量

  2. df_china_total = df_all.query("country=='中国' and province==''")

  3. df_china_total = df_china_total.sort_values('date',ascending=False)

  4. # df_china_total


  5. # 国外,按国家统计

  6. df_oversea = df_all.query("country!='中国'")

  7. df_oversea.fillna(value="", inplace=True)

  8. # df_oversea

进一步,我们可以梳理出海外国家的总计概况,同时,将国内的数据也提取出相应的字段。
  1. df_oversea_total = df_oversea.groupby(['date','dates'])['confirmed','cured','dead','current'].sum()

  2. df_oversea_total.reset_index(level=1,inplace=True)

  3. df_oversea_total['district'] = 'oversea'

  4. # df_oversea_total


  5. df_china_sum = df_china_total[['date','dates','confirmed','cured','dead','current']]

  6. df_china_sum.set_index('date',inplace=True)

  7. df_china_sum['district'] = 'China'

  8. # df_china_sum


  9. df_total = df_oversea_total.append(df_china_sum)

  10. df_total.sort_index(ascending=True,inplace=True)

  11. df_total

由于国外从1月16日起,才开始有统计数据,因此我们的可视化从这个日期开始。
  1. # 国外从 1月16日起,才开始有统计数据

  2. df_total_analysis = df_total['20200116':]

  3. df_total_analysis


疫情可视化

我们先来用 plotly express 对海外国家 和 国内情况的发展来做一个总的概览。
  1. fig_total = px.line(df_total_analysis, x='dates', y='confirmed', line_group='district',

  2. color='district', color_discrete_sequence=px.colors.qualitative.D3,

  3. hover_name='district',template='plotly_white',

  4. width=500,height=600,

  5. title=dict(text='Covid-19-trend',

  6. font=dict(size=16,color='#0071c1'),

  7. x=0.5)

  8. )


  9. fig_total.show()


从上面的趋势来看,国内基本趋稳了,而海外国家作为总体来看,还在快速发展。
这里仅仅是做简单的可视化,至于将中国和海外国家总体做对比分析,是否合理,这里只是个示例,不做进一步阐述。
上图中的曲线,并不能动态的演示变化过程,在 px.line 中,Lemon 也研究了下,暂时没有实现将曲线进行动态可视化的功能。
下面,Lemon 将用 Plotly 原生的功能来实现这个效果。

动态曲线演示疫情情况

在 Plotly 中,将曲线(Line)进行动态演示,需要通过几个步骤来实现
  1. 对初始状态进行可视化,每条曲线将起始的两个点绘制成曲线;

  2. 通过构造字典的形式,在 frames 中实现曲线的动态变化;

  3. 添加演示按钮,

代码如下:
  1. # 日期

  2. d = datetime.today().day

  3. m = datetime.today().month

  4. text_today = f'数据统计截止{m}月{d}日'


  5. # 海外数据

  6. df_oversea_analysis = df_total_analysis.query('district=="oversea"')

  7. # 国内数据

  8. df_cn_analysis = df_total_analysis.query('district=="China"')


  9. # 计算 最大的确诊人数

  10. y_max_cn = df_cn_analysis['confirmed'].max()

  11. y_max_oversea = df_oversea_analysis['confirmed'].max()

  12. y_max = max(y_max_cn,y_max_oversea)


  13. # China

  14. trace1 = go.Scatter(x=df_cn_analysis.index[:2],

  15. y=df_cn_analysis['confirmed'][:2],

  16. mode='lines',

  17. name='China',

  18. line=dict(width=1.5,

  19. color='#FFD300'))


  20. # oversea

  21. trace2 = go.Scatter(x = df_oversea_analysis.index[:2],

  22. y = df_oversea_analysis['confirmed'][:2],

  23. mode='lines', # markers+lines

  24. name='Oversea',

  25. line=dict(width=1.5))


  26. frames = [dict(data= [dict(type='scatter',

  27. x=df_cn_analysis.index[:k+1],

  28. y=df_cn_analysis['confirmed'][:k+1]),

  29. dict(type='scatter',

  30. x=df_oversea_analysis.index[:k+1],

  31. y=df_oversea_analysis['confirmed'][:k+1])],

  32. traces= [0, 1],

  33. # 0: frames[k]['data'][0],代表 trace1, 1:frames[k]['data'][1], trace2

  34. )for k in range(1, len(df_cn_analysis))]


  35. layout = go.Layout(width=500,

  36. height=600,

  37. showlegend=True,

  38. template='plotly_dark',

  39. hovermode='closest',

  40. updatemenus=[dict(type='buttons', showactive=False,

  41. y=1.10,

  42. x=1.15,

  43. xanchor='right',

  44. yanchor='top',

  45. pad=dict(t=0, r=10),

  46. buttons=[dict(label='Play',

  47. method='animate',

  48. args=[None,

  49. dict(frame=dict(duration=100,

  50. redraw=False),

  51. transition=dict(duration=1),

  52. fromcurrent=True,

  53. mode='immediate')])])],

  54. )


  55. layout.update(xaxis =dict(range=[df_cn_analysis.index[0],

  56. df_cn_analysis.index[len(df_cn_analysis)-1]+pd.Timedelta(days=2)

  57. ],

  58. autorange=False),

  59. yaxis =dict(range=[0, y_max*1.05], autorange=False))

  60. fig = go.Figure(data=[trace1, trace2], frames=frames, layout=layout)

  61. fig.show()

上面代码中, go.Layout 中的 duration 可以来控制按钮点击后变化的速度。
运行上述代码后,得到的效果如下:


曲线可以动起来了,是不是很棒啊。
上面的动态曲线是两条曲线的,这里给大家留一个作业,如果是 3条或者3条以上的曲线,该如何实现动态演示,大家可以思考下这个问题。
多条动态曲线的效果如下:


PS:如果曲线数量较少,你可以手动添加几条曲线,如果曲线数量较多,或者数量经常变化,则需要更加灵活的方式来实现。
为方便大家进行操作,Lemon 给大家提供了本文的 PDF 版内容(含完整的代码)以及数据文件,可以在公众号 「Python数据之道」后台回复数字 「660」进行获取。

相关阅读:
用 Plotly 动态柱状图来演示全球疫情变化趋势 | 付费阅读文章处女作
用 Python可视化神器 Plotly 动态演示全球疫情变化趋势
超火动态排序疫情变化图,这次我们用 Plotly来绘制


-------------------End-------------------


为防意外,Lemon 还有一个小号叫  「柠檬数据」(ID:LemonDataLab),会不定期分享关于数据的故事,也墙裂建议大家一并关注,以防突然某天就和 Lemon 失联了

扫描回复 “600

获取《Python知识手册

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存